home *** CD-ROM | disk | FTP | other *** search
/ Clickx 63 / Clickx 63.iso / software / multimedia / mirov204 / Miro_Installer.exe / xulrunner / chrome / toolkit.jar / content / global / customizeToolbar.js < prev    next >
Encoding:
Text File  |  2008-04-29  |  28.9 KB  |  972 lines

  1. //@line 40 "/e/xr19rel/WINNT_5.2_Depend/mozilla/toolkit/content/customizeToolbar.js"
  2.  
  3. const kRowMax = 4;
  4.  
  5. var gToolboxDocument = null;
  6. var gToolbox = null;
  7. var gCurrentDragOverItem = null;
  8. var gToolboxChanged = false;
  9. var gToolboxIconSize = false;
  10.  
  11. function onLoad()
  12. {
  13.   InitWithToolbox(window.arguments[0]);
  14.   repositionDialog();
  15. }
  16.  
  17. function InitWithToolbox(aToolbox)
  18. {
  19.   gToolbox = aToolbox;
  20.   gToolboxDocument = gToolbox.ownerDocument;
  21.   
  22.   gToolbox.addEventListener("draggesture", onToolbarDragGesture, false);
  23.   gToolbox.addEventListener("dragover", onToolbarDragOver, false);
  24.   gToolbox.addEventListener("dragexit", onToolbarDragExit, false);
  25.   gToolbox.addEventListener("dragdrop", onToolbarDragDrop, false);
  26.  
  27.   initDialog();
  28. }
  29.  
  30. function finishToolbarCustomization()
  31. {
  32.   removeToolboxListeners();
  33.   unwrapToolbarItems();
  34.   persistCurrentSets();
  35.   
  36.   notifyParentComplete();
  37. }
  38.  
  39. function initDialog()
  40. {
  41.   var mode = gToolbox.getAttribute("mode");
  42.   document.getElementById("modelist").value = mode;
  43.   gToolboxIconSize = gToolbox.getAttribute("iconsize");
  44.   var smallIconsCheckbox = document.getElementById("smallicons");
  45.   smallIconsCheckbox.checked = gToolboxIconSize == "small";
  46.   if (mode == "text")
  47.     smallIconsCheckbox.disabled = true;
  48.  
  49.   // Build up the palette of other items.
  50.   buildPalette();
  51.  
  52.   // Wrap all the items on the toolbar in toolbarpaletteitems.
  53.   wrapToolbarItems();
  54. }
  55.  
  56. function repositionDialog()
  57. {
  58.   // Position the dialog touching the bottom of the toolbox and centered with 
  59.   // it.
  60.   var width;
  61.   if (document.documentElement.hasAttribute("width"))
  62.     width = document.documentElement.getAttribute("width");
  63.   else
  64.     width = parseInt(document.documentElement.style.width);
  65.   var screenX = gToolbox.boxObject.screenX 
  66.                 + ((gToolbox.boxObject.width - width) / 2);
  67.   var screenY = gToolbox.boxObject.screenY + gToolbox.boxObject.height;
  68.  
  69.   window.moveTo(screenX, screenY);
  70. }
  71.  
  72. function removeToolboxListeners()
  73. {
  74.   gToolbox.removeEventListener("draggesture", onToolbarDragGesture, false);
  75.   gToolbox.removeEventListener("dragover", onToolbarDragOver, false);
  76.   gToolbox.removeEventListener("dragexit", onToolbarDragExit, false);
  77.   gToolbox.removeEventListener("dragdrop", onToolbarDragDrop, false);
  78. }
  79.  
  80. /**
  81.  * Invoke a callback on the toolbox to notify it that the dialog is done
  82.  * and going away.
  83.  */
  84. function notifyParentComplete()
  85. {
  86.   if ("customizeDone" in gToolbox)
  87.     gToolbox.customizeDone(gToolboxChanged);
  88. }
  89.  
  90. function toolboxChanged()
  91. {
  92.   gToolboxChanged = true;
  93.   if ("customizeChange" in gToolbox)
  94.     gToolbox.customizeChange();
  95. }
  96.  
  97. function getToolbarAt(i)
  98. {
  99.   return gToolbox.childNodes[i];
  100. }
  101.  
  102. /**
  103.  * Persist the current set of buttons in all customizable toolbars to
  104.  * localstore.
  105.  */
  106. function persistCurrentSets()
  107. {
  108.   if (!gToolboxChanged || gToolboxDocument.defaultView.closed)
  109.     return;
  110.  
  111.   var customCount = 0;
  112.   for (var i = 0; i < gToolbox.childNodes.length; ++i) {
  113.     // Look for customizable toolbars that need to be persisted.
  114.     var toolbar = getToolbarAt(i);
  115.     if (isCustomizableToolbar(toolbar)) {
  116.       // Calculate currentset and store it in the attribute.
  117.       var currentSet = toolbar.currentSet;
  118.       toolbar.setAttribute("currentset", currentSet);
  119.       
  120.       var customIndex = toolbar.hasAttribute("customindex");
  121.       if (customIndex) {
  122.         if (!toolbar.firstChild) {
  123.           // Remove custom toolbars whose contents have been removed.
  124.           gToolbox.removeChild(toolbar);
  125.           --i;
  126.         } else {
  127.           // Persist custom toolbar info on the <toolbarset/>
  128.           gToolbox.toolbarset.setAttribute("toolbar"+(++customCount),
  129.                                            toolbar.toolbarName + ":" + currentSet);
  130.           gToolboxDocument.persist(gToolbox.toolbarset.id, "toolbar"+customCount);
  131.         }
  132.       }
  133.  
  134.       if (!customIndex) {
  135.         // Persist the currentset attribute directly on hardcoded toolbars.
  136.         gToolboxDocument.persist(toolbar.id, "currentset");
  137.       }
  138.     }
  139.   }
  140.   
  141.   // Remove toolbarX attributes for removed toolbars.
  142.   while (gToolbox.toolbarset.hasAttribute("toolbar"+(++customCount))) {
  143.     gToolbox.toolbarset.removeAttribute("toolbar"+customCount);
  144.     gToolboxDocument.persist(gToolbox.toolbarset.id, "toolbar"+customCount);
  145.   }
  146. }
  147.  
  148. /**
  149.  * Wraps all items in all customizable toolbars in a toolbox.
  150.  */
  151. function wrapToolbarItems()
  152. {
  153.   for (var i = 0; i < gToolbox.childNodes.length; ++i) {
  154.     var toolbar = getToolbarAt(i);
  155.     if (isCustomizableToolbar(toolbar)) {
  156.       for (var k = 0; k < toolbar.childNodes.length; ++k) {
  157.         var item = toolbar.childNodes[k];
  158.  
  159. //@line 201 "/e/xr19rel/WINNT_5.2_Depend/mozilla/toolkit/content/customizeToolbar.js"
  160.  
  161.         if (isToolbarItem(item)) {
  162.           var nextSibling = item.nextSibling;
  163.           
  164.           var wrapper = wrapToolbarItem(item);
  165.           
  166.           if (nextSibling)
  167.             toolbar.insertBefore(wrapper, nextSibling);
  168.           else
  169.             toolbar.appendChild(wrapper);
  170.  
  171.           cleanupItemForToolbar(item, wrapper);
  172.         }
  173.       }
  174.     }
  175.   }
  176. }
  177.  
  178. /**
  179.  * Unwraps all items in all customizable toolbars in a toolbox.
  180.  */
  181. function unwrapToolbarItems()
  182. {
  183.   var paletteItems = gToolbox.getElementsByTagName("toolbarpaletteitem");
  184.   var paletteItem;
  185.   while ((paletteItem = paletteItems.item(0)) != null) {
  186.     var toolbarItem = paletteItem.firstChild;
  187.  
  188.     if (paletteItem.hasAttribute("itemdisabled"))
  189.       toolbarItem.disabled = true;
  190.  
  191.     if (paletteItem.hasAttribute("itemcommand"))
  192.       toolbarItem.setAttribute("command", paletteItem.getAttribute("itemcommand"));
  193.  
  194.     paletteItem.parentNode.replaceChild(toolbarItem, paletteItem);
  195.   }
  196. }
  197.  
  198. /**
  199.  * Creates a wrapper that can be used to contain a toolbaritem and prevent
  200.  * it from receiving UI events.
  201.  */
  202. function createWrapper(aId)
  203. {
  204.   var wrapper = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  205.                                          "toolbarpaletteitem");
  206.  
  207.   wrapper.id = "wrapper-"+aId;  
  208.   return wrapper;
  209. }
  210.  
  211. /**
  212.  * Wraps an item that has been cloned from a template and adds
  213.  * it to the end of a row in the palette.
  214.  */
  215. function wrapPaletteItem(aPaletteItem, aCurrentRow, aSpacer)
  216. {
  217.   var wrapper = createWrapper(aPaletteItem.id);
  218.  
  219.   wrapper.setAttribute("flex", 1);
  220.   wrapper.setAttribute("align", "center");
  221.   wrapper.setAttribute("pack", "center");
  222.   wrapper.setAttribute("minheight", "0");
  223.   wrapper.setAttribute("minwidth", "0");
  224.  
  225.   document.adoptNode(aPaletteItem);
  226.   wrapper.appendChild(aPaletteItem);
  227.   
  228.   // XXX We need to call this AFTER the palette item has been appended
  229.   // to the wrapper or else we crash dropping certain buttons on the 
  230.   // palette due to removal of the command and disabled attributes - JRH
  231.   cleanUpItemForPalette(aPaletteItem, wrapper);
  232.  
  233.   if (aSpacer)
  234.     aCurrentRow.insertBefore(wrapper, aSpacer);
  235.   else
  236.     aCurrentRow.appendChild(wrapper);
  237.  
  238. }
  239.  
  240. /**
  241.  * Wraps an item that is currently on a toolbar and replaces the item
  242.  * with the wrapper. This is not used when dropping items from the palette,
  243.  * only when first starting the dialog and wrapping everything on the toolbars.
  244.  */
  245. function wrapToolbarItem(aToolbarItem)
  246. {
  247.   var wrapper = createWrapper(aToolbarItem.id);
  248.   gToolboxDocument.adoptNode(wrapper);
  249.  
  250.   wrapper.flex = aToolbarItem.flex;
  251.  
  252.   if (aToolbarItem.parentNode)
  253.     aToolbarItem.parentNode.removeChild(aToolbarItem);
  254.   
  255.   wrapper.appendChild(aToolbarItem);
  256.   
  257.   return wrapper;
  258. }
  259.  
  260. /**
  261.  * Get the list of ids for the current set of items on each toolbar.
  262.  */
  263. function getCurrentItemIds()
  264. {
  265.   var currentItems = {};
  266.   for (var i = 0; i < gToolbox.childNodes.length; ++i) {
  267.     var toolbar = getToolbarAt(i);
  268.     if (isCustomizableToolbar(toolbar)) {
  269.       var child = toolbar.firstChild;
  270.       while (child) {
  271.         if (isToolbarItem(child))
  272.           currentItems[child.id] = 1;
  273.         child = child.nextSibling;
  274.       }
  275.     }
  276.   }
  277.   return currentItems;
  278. }
  279.  
  280. /**
  281.  * Builds the palette of draggable items that are not yet in a toolbar.
  282.  */
  283. function buildPalette()
  284. {
  285.   // Empty the palette first.
  286.   var paletteBox = document.getElementById("palette-box");
  287.   while (paletteBox.lastChild)
  288.     paletteBox.removeChild(paletteBox.lastChild);
  289.  
  290.   var currentRow = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  291.                                             "hbox");
  292.   currentRow.setAttribute("class", "paletteRow");
  293.  
  294.   // Add the toolbar separator item.
  295.   var templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  296.                                               "toolbarseparator");
  297.   templateNode.id = "separator";
  298.   wrapPaletteItem(templateNode, currentRow, null);
  299.  
  300.   // Add the toolbar spring item.
  301.   templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  302.                                               "toolbarspring");
  303.   templateNode.id = "spring";
  304.   templateNode.flex = 1;
  305.   wrapPaletteItem(templateNode, currentRow, null);
  306.  
  307.   // Add the toolbar spacer item.
  308.   templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  309.                                               "toolbarspacer");
  310.   templateNode.id = "spacer";
  311.   templateNode.flex = 1;
  312.   wrapPaletteItem(templateNode, currentRow, null);
  313.  
  314.   var rowSlot = 3;
  315.  
  316.   var currentItems = getCurrentItemIds();
  317.   templateNode = gToolbox.palette.firstChild;
  318.   while (templateNode) {
  319.     // Check if the item is already in a toolbar before adding it to the palette.
  320.     if (!(templateNode.id in currentItems)) {
  321.       var paletteItem = templateNode.cloneNode(true);
  322.  
  323.       if (rowSlot == kRowMax) {
  324.         // Append the old row.
  325.         paletteBox.appendChild(currentRow);
  326.  
  327.         // Make a new row.
  328.         currentRow = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  329.                                               "hbox");
  330.         currentRow.setAttribute("class", "paletteRow");
  331.         rowSlot = 0;
  332.       }
  333.  
  334.       ++rowSlot;
  335.       wrapPaletteItem(paletteItem, currentRow, null);
  336.     }
  337.     
  338.     templateNode = templateNode.nextSibling;
  339.   }
  340.  
  341.   if (currentRow) { 
  342.     fillRowWithFlex(currentRow);
  343.     paletteBox.appendChild(currentRow);
  344.   }
  345. }
  346.  
  347. /**
  348.  * Creates a new palette item for a cloned template node and
  349.  * adds it to the last slot in the palette.
  350.  */
  351. function appendPaletteItem(aItem)
  352. {
  353.   var paletteBox = document.getElementById("palette-box");
  354.   var lastRow = paletteBox.lastChild;
  355.   var lastSpacer = lastRow.lastChild;
  356.    
  357.   if (lastSpacer.localName != "spacer") {
  358.     // The current row is full, so we have to create a new row.
  359.     lastRow = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  360.                                         "hbox");
  361.     lastRow.setAttribute("class", "paletteRow");
  362.     paletteBox.appendChild(lastRow);
  363.     
  364.     wrapPaletteItem(aItem, lastRow, null);
  365.  
  366.     fillRowWithFlex(lastRow);
  367.   } else {
  368.     // Decrement the flex of the last spacer or remove it entirely.
  369.     var flex = lastSpacer.getAttribute("flex");
  370.     if (flex == 1) {
  371.       lastRow.removeChild(lastSpacer);
  372.       lastSpacer = null;
  373.     } else
  374.       lastSpacer.setAttribute("flex", --flex);
  375.  
  376.     // Insert the wrapper where the last spacer was.
  377.     wrapPaletteItem(aItem, lastRow, lastSpacer);
  378.   }
  379. }
  380.  
  381. function fillRowWithFlex(aRow)
  382. {
  383.   var remainingFlex = kRowMax - aRow.childNodes.length;
  384.   if (remainingFlex > 0) {
  385.     var spacer = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  386.                                           "spacer");
  387.     spacer.setAttribute("flex", remainingFlex);
  388.     aRow.appendChild(spacer);
  389.   }
  390. }
  391.  
  392. /**
  393.  * Makes sure that an item that has been cloned from a template
  394.  * is stripped of all properties that may adversely affect it's
  395.  * appearance in the palette.
  396.  */
  397. function cleanUpItemForPalette(aItem, aWrapper)
  398. {
  399.   aWrapper.setAttribute("place", "palette");
  400.   setWrapperType(aItem, aWrapper);
  401.  
  402.   if (aItem.hasAttribute("title"))
  403.     aWrapper.setAttribute("title", aItem.getAttribute("title"));
  404.   else if (isSpecialItem(aItem)) {
  405.     var stringBundle = document.getElementById("stringBundle");
  406.     var title = stringBundle.getString(aItem.id + "Title");
  407.     aWrapper.setAttribute("title", title);
  408.   }
  409.   
  410.   // Remove attributes that screw up our appearance.
  411.   aItem.removeAttribute("command");
  412.   aItem.removeAttribute("observes");
  413.   aItem.removeAttribute("disabled");
  414.   aItem.removeAttribute("type");
  415.   
  416.   if (aItem.localName == "toolbaritem" && aItem.firstChild) {
  417.     aItem.firstChild.removeAttribute("observes");
  418.  
  419.     // So the throbber doesn't throb in the dialog,
  420.     // cute as that may be...
  421.     aItem.firstChild.removeAttribute("busy");
  422.   }
  423. }
  424.  
  425. /**
  426.  * Makes sure that an item that has been cloned from a template
  427.  * is stripped of all properties that may adversely affect it's
  428.  * appearance in the toolbar.  Store critical properties on the 
  429.  * wrapper so they can be put back on the item when we're done.
  430.  */
  431. function cleanupItemForToolbar(aItem, aWrapper)
  432. {
  433.   setWrapperType(aItem, aWrapper);
  434.   aWrapper.setAttribute("place", "toolbar");
  435.  
  436.   if (aItem.hasAttribute("command")) {
  437.     aWrapper.setAttribute("itemcommand", aItem.getAttribute("command"));
  438.     aItem.removeAttribute("command");
  439.   }
  440.  
  441.   if (aItem.disabled) {
  442.     aWrapper.setAttribute("itemdisabled", "true");
  443.     aItem.disabled = false;
  444.   }
  445. }
  446.  
  447. function setWrapperType(aItem, aWrapper)
  448. {
  449.   if (aItem.localName == "toolbarseparator") {
  450.     aWrapper.setAttribute("type", "separator");
  451.   } else if (aItem.localName == "toolbarspring") {
  452.     aWrapper.setAttribute("type", "spring");
  453.   } else if (aItem.localName == "toolbarspacer") {
  454.     aWrapper.setAttribute("type", "spacer");
  455.   } else if (aItem.localName == "toolbaritem" && aItem.firstChild) {
  456.     aWrapper.setAttribute("type", aItem.firstChild.localName);
  457.   }
  458. }
  459.  
  460. function setDragActive(aItem, aValue)
  461. {
  462.   var node = aItem;
  463.   var direction = window.getComputedStyle(aItem, null).direction;
  464.   var value = direction == "ltr"? "left" : "right";
  465.   if (aItem.localName == "toolbar") {
  466.     node = aItem.lastChild;
  467.     value = direction == "ltr"? "right" : "left";
  468.   }
  469.   
  470.   if (!node)
  471.     return;
  472.   
  473.   if (aValue) {
  474.     if (!node.hasAttribute("dragover"))
  475.       node.setAttribute("dragover", value);
  476.   } else {
  477.     node.removeAttribute("dragover");
  478.   }
  479. }
  480.  
  481. function addNewToolbar()
  482. {
  483.   var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  484.                                 .getService(Components.interfaces.nsIPromptService);
  485.  
  486.   var stringBundle = document.getElementById("stringBundle");
  487.   var message = stringBundle.getString("enterToolbarName");
  488.   var title = stringBundle.getString("enterToolbarTitle");
  489.  
  490.   var name = {};
  491.  
  492.   // Quitting from the toolbar dialog while the new toolbar prompt is up
  493.   // can cause things to become unresponsive on the Mac. Until dialog modality
  494.   // is fixed (395465), disable the "Done" button explicitly.
  495.   var doneButton = document.getElementById("donebutton");
  496.   doneButton.disabled = true;
  497.  
  498.   while (true) {
  499.  
  500.     if (!promptService.prompt(window, title, message, name, null, {})) {
  501.       doneButton.disabled = false;
  502.       return;
  503.     }
  504.     
  505.     if (!name.value) {
  506.       message = stringBundle.getFormattedString("enterToolbarBlank", [name.value]);
  507.       continue;
  508.     }
  509.  
  510.     var dupeFound = false;
  511.  
  512.      // Check for an existing toolbar with the same display name
  513.     for (i = 0; i < gToolbox.childNodes.length; ++i) {
  514.       var toolbar = gToolbox.childNodes[i];
  515.       var toolbarName = toolbar.getAttribute("toolbarname");
  516.  
  517.       if (toolbarName == name.value &&
  518.           toolbar.getAttribute("type") != "menubar" &&
  519.           toolbar.nodeName == 'toolbar') {
  520.         dupeFound = true;
  521.         break;
  522.       }
  523.     }
  524.  
  525.     if (!dupeFound)
  526.       break;
  527.  
  528.     message = stringBundle.getFormattedString("enterToolbarDup", [name.value]);
  529.   }
  530.     
  531.   gToolbox.appendCustomToolbar(name.value, "");
  532.   
  533.   toolboxChanged();
  534.  
  535.   doneButton.disabled = false;
  536. }
  537.  
  538. /**
  539.  * Restore the default set of buttons to fixed toolbars,
  540.  * remove all custom toolbars, and rebuild the palette.
  541.  */
  542. function restoreDefaultSet()
  543. {
  544.   // Save disabled/command states, because we're
  545.   // going to recreate the wrappers and lose this
  546.   var savedAttributes = saveItemAttributes(["itemdisabled", "itemcommand"]);
  547.  
  548.   // Remove all of the customized toolbars.
  549.   var child = gToolbox.lastChild;
  550.   while (child) {
  551.     if (child.hasAttribute("customindex")) {
  552.       var thisChild = child;
  553.       child = child.previousSibling;
  554.       gToolbox.removeChild(thisChild);
  555.     } else {
  556.       child = child.previousSibling;
  557.     }
  558.   }
  559.  
  560.   // Restore the defaultset for fixed toolbars.
  561.   var toolbar = gToolbox.firstChild;
  562.   while (toolbar) {
  563.     if (isCustomizableToolbar(toolbar)) {
  564.       var defaultSet = toolbar.getAttribute("defaultset");
  565.       if (defaultSet)
  566.         toolbar.currentSet = defaultSet;
  567.     }
  568.     toolbar = toolbar.nextSibling;
  569.   }
  570.  
  571.   // Restore the default icon size and mode.
  572.   var defaultMode = gToolbox.getAttribute("defaultmode");
  573.   var defaultIconsSmall = gToolbox.getAttribute("defaulticonsize") == "small";
  574.  
  575.   updateIconSize(defaultIconsSmall, true);
  576.   document.getElementById("smallicons").checked = defaultIconsSmall;
  577.   updateToolbarMode(defaultMode, true);
  578.   document.getElementById("modelist").value = defaultMode;
  579.  
  580.   // Now rebuild the palette.
  581.   buildPalette();
  582.  
  583.   // Now re-wrap the items on the toolbar.
  584.   wrapToolbarItems();
  585.  
  586.   // Restore the disabled and command states
  587.   restoreItemAttributes(["itemdisabled", "itemcommand"], savedAttributes);
  588.  
  589.   toolboxChanged();
  590. }
  591.  
  592. function saveItemAttributes(aAttributeList)
  593. {
  594.   var items = [];
  595.   var paletteItems = gToolbox.getElementsByTagName("toolbarpaletteitem");
  596.   for (var i = 0; i < paletteItems.length; i++) {
  597.     var paletteItem = paletteItems.item(i);
  598.     for (var j = 0; j < aAttributeList.length; j++) {
  599.       var attr = aAttributeList[j];
  600.       if (paletteItem.hasAttribute(attr)) {
  601.         items.push([paletteItem.id, attr, paletteItem.getAttribute(attr)]);
  602.       }
  603.     }
  604.   }
  605.   return items;
  606. }
  607.  
  608. function restoreItemAttributes(aAttributeList, aSavedAttrList)
  609. {
  610.   var paletteItems = gToolbox.getElementsByTagName("toolbarpaletteitem");
  611.  
  612.   for (var i = 0; i < paletteItems.length; i++) {
  613.     var paletteItem = paletteItems.item(i);
  614.  
  615.     // if the item is supposed to have this, it'll get
  616.     // restored from the saved list
  617.     for (var j = 0; j < aAttributeList.length; j++)
  618.       paletteItem.removeAttribute(aAttributeList[j]);
  619.  
  620.     for (var j = 0; j < aSavedAttrList.length; j++) {
  621.       var savedAttr = aSavedAttrList[j];
  622.       if (paletteItem.id == savedAttr[0]) {
  623.         paletteItem.setAttribute(savedAttr[1], savedAttr[2]);
  624.       }
  625.     }
  626.   }
  627. }
  628.  
  629. function updateIconSize(aUseSmallIcons, localDefault)
  630. {
  631.   gToolboxIconSize = aUseSmallIcons ? "small" : "large";
  632.   
  633.   setAttribute(gToolbox, "iconsize", gToolboxIconSize);
  634.   gToolboxDocument.persist(gToolbox.id, "iconsize");
  635.   
  636.   for (var i = 0; i < gToolbox.childNodes.length; ++i) {
  637.     var toolbar = getToolbarAt(i);
  638.     if (isCustomizableToolbar(toolbar)) {
  639.       var toolbarIconSize = (localDefault && toolbar.hasAttribute("defaulticonsize")) ?
  640.                             toolbar.getAttribute("defaulticonsize") :
  641.                             gToolboxIconSize;
  642.       setAttribute(toolbar, "iconsize", toolbarIconSize);
  643.       gToolboxDocument.persist(toolbar.id, "iconsize");
  644.     }
  645.   }
  646. }
  647.  
  648. function updateToolbarMode(aModeValue, localDefault)
  649. {
  650.   setAttribute(gToolbox, "mode", aModeValue);
  651.   gToolboxDocument.persist(gToolbox.id, "mode");
  652.  
  653.   for (var i = 0; i < gToolbox.childNodes.length; ++i) {
  654.     var toolbar = getToolbarAt(i);
  655.     if (isCustomizableToolbar(toolbar)) {
  656.       var toolbarMode = (localDefault && toolbar.hasAttribute("defaultmode")) ?
  657.                         toolbar.getAttribute("defaultmode") :
  658.                         aModeValue;
  659.       setAttribute(toolbar, "mode", toolbarMode);
  660.       gToolboxDocument.persist(toolbar.id, "mode");
  661.     }
  662.   }
  663.  
  664.   var iconSizeCheckbox = document.getElementById("smallicons");
  665.   iconSizeCheckbox.disabled = aModeValue == "text";
  666. }
  667.  
  668.  
  669. function setAttribute(aElt, aAttr, aVal)
  670. {
  671.  if (aVal)
  672.     aElt.setAttribute(aAttr, aVal);
  673.   else
  674.     aElt.removeAttribute(aAttr);
  675. }
  676.  
  677. function isCustomizableToolbar(aElt)
  678. {
  679.   return aElt.localName == "toolbar" &&
  680.          aElt.getAttribute("customizable") == "true";
  681. }
  682.  
  683. function isSpecialItem(aElt)
  684. {
  685.   return aElt.localName == "toolbarseparator" ||
  686.          aElt.localName == "toolbarspring" ||
  687.          aElt.localName == "toolbarspacer";
  688. }
  689.  
  690. function isToolbarItem(aElt)
  691. {
  692.   return aElt.localName == "toolbarbutton" ||
  693.          aElt.localName == "toolbaritem" ||
  694.          aElt.localName == "toolbarseparator" ||
  695.          aElt.localName == "toolbarspring" ||
  696.          aElt.localName == "toolbarspacer";
  697. }
  698.  
  699. ///////////////////////////////////////////////////////////////////////////
  700. //// Drag and Drop observers
  701.  
  702. function onToolbarDragGesture(aEvent)
  703. {
  704.   nsDragAndDrop.startDrag(aEvent, dragStartObserver);
  705. }
  706.  
  707. function onToolbarDragOver(aEvent)
  708. {
  709.   nsDragAndDrop.dragOver(aEvent, toolbarDNDObserver);
  710. }
  711.  
  712. function onToolbarDragDrop(aEvent)
  713. {
  714.   nsDragAndDrop.drop(aEvent, toolbarDNDObserver);
  715. }
  716.  
  717. function onToolbarDragExit(aEvent)
  718. {
  719.   if (gCurrentDragOverItem)
  720.     setDragActive(gCurrentDragOverItem, false);
  721. }
  722.  
  723. var dragStartObserver =
  724. {
  725.   onDragStart: function (aEvent, aXferData, aDragAction) {
  726.     var documentId = gToolboxDocument.documentElement.id;
  727.     
  728.     var item = aEvent.target;
  729.     while (item && item.localName != "toolbarpaletteitem")
  730.       item = item.parentNode;
  731.     
  732.     item.setAttribute("dragactive", "true");
  733.     
  734.     aXferData.data = new TransferDataSet();
  735.     var data = new TransferData();
  736.     data.addDataForFlavour("text/toolbarwrapper-id/"+documentId, item.firstChild.id);
  737.     aXferData.data.push(data);
  738.     aDragAction.action = Components.interfaces.nsIDragService.DRAGDROP_ACTION_MOVE;
  739.   }
  740. }
  741.  
  742. var toolbarDNDObserver =
  743. {
  744.   onDragOver: function (aEvent, aFlavour, aDragSession)
  745.   {
  746.     var toolbar = aEvent.target;
  747.     var dropTarget = aEvent.target;
  748.     while (toolbar && toolbar.localName != "toolbar") {
  749.       dropTarget = toolbar;
  750.       toolbar = toolbar.parentNode;
  751.     }
  752.     
  753.     var previousDragItem = gCurrentDragOverItem;
  754.  
  755.     // Make sure we are dragging over a customizable toolbar.
  756.     if (!isCustomizableToolbar(toolbar)) {
  757.       gCurrentDragOverItem = null;
  758.       return;
  759.     }
  760.     
  761.     if (dropTarget.localName == "toolbar") {
  762.       gCurrentDragOverItem = dropTarget;
  763.     } else {
  764.       gCurrentDragOverItem = null;
  765.  
  766.       var direction = window.getComputedStyle(dropTarget.parentNode, null).direction;
  767.       var dropTargetCenter = dropTarget.boxObject.x + (dropTarget.boxObject.width / 2);
  768.       if (direction == "ltr")
  769.         dragAfter = aEvent.clientX > dropTargetCenter;
  770.       else
  771.         dragAfter = aEvent.clientX < dropTargetCenter;
  772.         
  773.       if (dragAfter) {
  774.         gCurrentDragOverItem = dropTarget.nextSibling;
  775.         if (!gCurrentDragOverItem)
  776.           gCurrentDragOverItem = toolbar;
  777.       } else
  778.         gCurrentDragOverItem = dropTarget;
  779.     }    
  780.  
  781.     if (previousDragItem && gCurrentDragOverItem != previousDragItem) {
  782.       setDragActive(previousDragItem, false);
  783.     }
  784.     
  785.     setDragActive(gCurrentDragOverItem, true);
  786.     
  787.     aDragSession.canDrop = true;
  788.   },
  789.   
  790.   onDrop: function (aEvent, aXferData, aDragSession)
  791.   {
  792.     if (!gCurrentDragOverItem)
  793.       return;
  794.     
  795.     setDragActive(gCurrentDragOverItem, false);
  796.  
  797.     var draggedItemId = aXferData.data;
  798.     if (gCurrentDragOverItem.id == draggedItemId)
  799.       return;
  800.  
  801.     var toolbar = aEvent.target;
  802.     while (toolbar.localName != "toolbar")
  803.       toolbar = toolbar.parentNode;
  804.  
  805.     var draggedPaletteWrapper = document.getElementById("wrapper-"+draggedItemId);       
  806.     if (!draggedPaletteWrapper) {
  807.       // The wrapper has been dragged from the toolbar.
  808.       
  809.       // Get the wrapper from the toolbar document and make sure that
  810.       // it isn't being dropped on itself.
  811.       var wrapper = gToolboxDocument.getElementById("wrapper-"+draggedItemId);
  812.       if (wrapper == gCurrentDragOverItem)
  813.         return;
  814.  
  815.       // Don't allow static kids (e.g., the menubar) to move.
  816.       if (wrapper.parentNode.firstPermanentChild && wrapper.parentNode.firstPermanentChild.id == wrapper.firstChild.id)
  817.         return;
  818.       if (wrapper.parentNode.lastPermanentChild && wrapper.parentNode.lastPermanentChild.id == wrapper.firstChild.id)
  819.         return;
  820.  
  821.       // Remove the item from it's place in the toolbar.
  822.       wrapper.parentNode.removeChild(wrapper);
  823.  
  824.       // Determine which toolbar we are dropping on.
  825.       var dropToolbar = null;
  826.       if (gCurrentDragOverItem.localName == "toolbar")
  827.         dropToolbar = gCurrentDragOverItem;
  828.       else
  829.         dropToolbar = gCurrentDragOverItem.parentNode;
  830.       
  831.       // Insert the item into the toolbar.
  832.       if (gCurrentDragOverItem != dropToolbar)
  833.         dropToolbar.insertBefore(wrapper, gCurrentDragOverItem);
  834.       else
  835.         dropToolbar.appendChild(wrapper);
  836.     } else {
  837.       // The item has been dragged from the palette
  838.       
  839.       // Create a new wrapper for the item. We don't know the id yet.
  840.       var wrapper = createWrapper("");
  841.       gToolboxDocument.adoptNode(wrapper);
  842.  
  843.       // Ask the toolbar to clone the item's template, place it inside the wrapper, and insert it in the toolbar.
  844.       var newItem = toolbar.insertItem(draggedItemId, gCurrentDragOverItem == toolbar ? null : gCurrentDragOverItem, wrapper);
  845.       
  846.       // Prepare the item and wrapper to look good on the toolbar.
  847.       cleanupItemForToolbar(newItem, wrapper);
  848.       wrapper.id = "wrapper-"+newItem.id;
  849.       wrapper.flex = newItem.flex;
  850.  
  851.       // Remove the wrapper from the palette.
  852.       var currentRow = draggedPaletteWrapper.parentNode;
  853.       if (draggedItemId != "separator" &&
  854.           draggedItemId != "spring" &&
  855.           draggedItemId != "spacer")
  856.       {
  857.         currentRow.removeChild(draggedPaletteWrapper);
  858.  
  859.         while (currentRow) {
  860.           // Pull the first child of the next row up
  861.           // into this row.
  862.           var nextRow = currentRow.nextSibling;
  863.           
  864.           if (!nextRow) {
  865.             var last = currentRow.lastChild;
  866.             var first = currentRow.firstChild;
  867.             if (first == last) {
  868.               // Kill the row.
  869.               currentRow.parentNode.removeChild(currentRow);
  870.               break;
  871.             }
  872.  
  873.             if (last.localName == "spacer") {
  874.               var flex = last.getAttribute("flex");
  875.               last.setAttribute("flex", ++flex);
  876.               // Reflow doesn't happen for some reason.  Trigger it with a hide/show. ICK! -dwh
  877.               last.hidden = true;
  878.               last.hidden = false;
  879.               break;
  880.             } else {
  881.               // Make a spacer and give it a flex of 1.
  882.               var spacer = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  883.                                                     "spacer");
  884.               spacer.setAttribute("flex", "1");
  885.               currentRow.appendChild(spacer);
  886.             }
  887.             break;
  888.           }
  889.           
  890.           currentRow.appendChild(nextRow.firstChild);
  891.           currentRow = currentRow.nextSibling;
  892.         }
  893.       }
  894.     }
  895.     
  896.     gCurrentDragOverItem = null;
  897.  
  898.     toolboxChanged();
  899.   },
  900.   
  901.   _flavourSet: null,
  902.   
  903.   getSupportedFlavours: function ()
  904.   {
  905.     if (!this._flavourSet) {
  906.       this._flavourSet = new FlavourSet();
  907.       var documentId = gToolboxDocument.documentElement.id;
  908.       this._flavourSet.appendFlavour("text/toolbarwrapper-id/"+documentId);
  909.     }
  910.     return this._flavourSet;
  911.   }
  912. }
  913.  
  914. var paletteDNDObserver =
  915. {
  916.   onDragOver: function (aEvent, aFlavour, aDragSession)
  917.   {
  918.     aDragSession.canDrop = true;
  919.   },
  920.   
  921.   onDrop: function(aEvent, aXferData, aDragSession)
  922.   {
  923.     var itemId = aXferData.data;
  924.     
  925.     var wrapper = gToolboxDocument.getElementById("wrapper-"+itemId);
  926.     if (wrapper) {
  927.       // Don't allow static kids (e.g., the menubar) to move.
  928.       if (wrapper.parentNode.firstPermanentChild && wrapper.parentNode.firstPermanentChild.id == wrapper.firstChild.id)
  929.         return;
  930.       if (wrapper.parentNode.lastPermanentChild && wrapper.parentNode.lastPermanentChild.id == wrapper.firstChild.id)
  931.         return;
  932.  
  933.       // The item was dragged out of the toolbar.
  934.       wrapper.parentNode.removeChild(wrapper);
  935.       
  936.       var wrapperType = wrapper.getAttribute("type");
  937.       if (wrapperType != "separator" &&
  938.           wrapperType != "spacer" &&
  939.           wrapperType != "spring") {
  940.         // Find the template node in the toolbox palette
  941.         var templateNode = gToolbox.palette.firstChild;
  942.         while (templateNode) {
  943.           if (templateNode.id == itemId)
  944.             break;
  945.           templateNode = templateNode.nextSibling;
  946.         }
  947.         if (!templateNode)
  948.           return;
  949.         
  950.         // Clone the template and add it to our palette.
  951.         var paletteItem = templateNode.cloneNode(true);
  952.         appendPaletteItem(paletteItem);
  953.       }
  954.     }
  955.     
  956.     toolboxChanged();
  957.   },
  958.   
  959.   _flavourSet: null,
  960.   
  961.   getSupportedFlavours: function ()
  962.   {
  963.     if (!this._flavourSet) {
  964.       this._flavourSet = new FlavourSet();
  965.       var documentId = gToolboxDocument.documentElement.id;
  966.       this._flavourSet.appendFlavour("text/toolbarwrapper-id/"+documentId);
  967.     }
  968.     return this._flavourSet;
  969.   }
  970. }
  971.  
  972.